#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
云侧WebSocket服务器
用于接收和处理端侧发送的语音数据
支持ASR任务管理和音频数据传输
"""

import asyncio
import websockets
import json
import base64
import logging
import wave
import os
import uuid
import time
from datetime import datetime, timezone
from typing import Dict, Set, List, Optional
from services.asr import ASRService
from services.nlu import NLUService

# 配置日志
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)


class CloudWebSocketServer:
    def __init__(self, host="0.0.0.0", port=8088):
        self.host = host
        self.port = port
        self.clients: Set[websockets.WebSocketServerProtocol] = set()
        self.audio_buffers: Dict[int, List[dict]] = {}
        self.task_states: Dict[int, dict] = {}  # 存储客户端任务状态
        self.robot_clients: Dict[str, websockets.WebSocketServerProtocol] = {}  # robot_id到客户端的映射
        self.audio_save_dir = "received_audio"
        self.asr_service = ASRService()  # 初始化ASR服务
        self.nlu_service = NLUService()  # 初始化NLU服务

        # 创建音频保存目录
        os.makedirs(self.audio_save_dir, exist_ok=True)

    async def handle_client(self, websocket, path):
        """处理客户端连接"""
        client_id = id(websocket)
        self.clients.add(websocket)
        self.audio_buffers[client_id] = []
        self.task_states[client_id] = {
            "current_task_id": None,
            "is_recording": False,
            "start_time": None,
            "robot_id": None,  # 添加robot_id字段
        }

        logger.info(f"客户端 {client_id} 已连接，当前连接数: {len(self.clients)}")

        try:
            async for message in websocket:
                await self.process_message(websocket, client_id, message)
        except websockets.exceptions.ConnectionClosed:
            logger.info(f"客户端 {client_id} 连接已关闭")
        except Exception as e:
            logger.error(f"处理客户端 {client_id} 消息时出错: {e}")
        finally:
            # 清理robot映射
            if client_id in self.task_states and self.task_states[client_id].get("robot_id"):
                robot_id = self.task_states[client_id]["robot_id"]
                if robot_id in self.robot_clients:
                    del self.robot_clients[robot_id]
                    logger.info(f"已清理robot {robot_id} 的客户端映射")

            self.clients.remove(websocket)
            if client_id in self.audio_buffers:
                del self.audio_buffers[client_id]
            if client_id in self.task_states:
                del self.task_states[client_id]
            logger.info(f"客户端 {client_id} 已断开，当前连接数: {len(self.clients)}")

    async def process_message(self, websocket, client_id, message):
        """处理接收到的消息"""
        try:
            # 尝试解析为JSON消息
            if isinstance(message, str):
                data = json.loads(message)
                await self.handle_json_message(websocket, client_id, data)
            else:
                # 二进制消息，作为音频数据处理
                await self.handle_binary_audio(websocket, client_id, message)

        except json.JSONDecodeError:
            # 如果不是JSON，可能是二进制音频数据
            await self.handle_binary_audio(websocket, client_id, message)
        except Exception as e:
            logger.error(f"处理消息时出错: {e}")
            await self.send_error(websocket, f"处理消息时出错: {str(e)}")

    async def handle_json_message(self, websocket, client_id, data):
        """处理JSON格式消息"""
        try:
            # 检查是否是ASR任务管理消息
            if "header" in data and "action" in data["header"]:
                action = data["header"].get("action")
                if action == "nlu-result":
                    # 处理NLU结果分发
                    await self.handle_nlu_result_distribution(websocket, client_id, data)
                elif action == "register-robot":
                    # 处理robot注册
                    await self.handle_robot_registration(websocket, client_id, data)
                else:
                    # 处理其他ASR任务管理消息
                    await self.handle_asr_task_message(websocket, client_id, data)
            else:
                # 处理传统消息格式
                message_type = data.get("type")

                if message_type == "audio_data":
                    await self.handle_audio_data(websocket, client_id, data)
                elif message_type == "text_message":
                    await self.handle_text_message(websocket, client_id, data)
                elif message_type == "start_recording":
                    await self.handle_start_recording(websocket, client_id, data)
                elif message_type == "stop_recording":
                    await self.handle_stop_recording(websocket, client_id, data)
                elif message_type == "finish-task":
                    # 处理finish-task消息
                    sequence_id = data.get("sequence_id")
                    robot_id = data.get("robot_id")
                    action = data.get("action")
                    task_id = data.get("task_id")

                    logger.info(
                        f"收到finish-task消息: sequence_id={sequence_id}, robot_id={robot_id}, action={action}, task_id={task_id}")

                    # 调用handle_finish_task方法
                    await self.handle_finish_task(websocket, client_id, data, task_id)
                elif message_type == "test":
                    # 处理测试消息
                    logger.info(f"收到测试消息: {data.get('content', 'N/A')}")
                    test_response = {
                        "type": "test_response",
                        "status": "success",
                        "message": "测试消息已收到",
                        "timestamp": datetime.now().isoformat()
                    }
                    await websocket.send(json.dumps(test_response, ensure_ascii=False))
                # 移除心跳消息处理
                else:
                    await self.send_error(websocket, f"未知的消息类型: {message_type}")

        except Exception as e:
            logger.error(f"处理JSON消息时出错: {e}")
            await self.send_error(websocket, f"处理JSON消息时出错: {str(e)}")

    async def handle_asr_task_message(self, websocket, client_id, data):
        """处理ASR任务管理消息"""
        action = data["header"].get("action")
        task_id = data["header"].get("task_id")

        if action == "run-task":
            await self.handle_run_task(websocket, client_id, data, task_id)
        elif action == "finish-task":
            await self.handle_finish_task(websocket, client_id, data, task_id)
        else:
            logger.warning(f"未知的ASR任务动作: {action}")

    async def handle_run_task(self, websocket, client_id, data, task_id):
        """处理开始任务消息"""
        logger.info(f"客户端 {client_id} 开始ASR任务: {task_id}")

        # 更新任务状态
        self.task_states[client_id]["current_task_id"] = task_id
        self.task_states[client_id]["is_recording"] = True
        self.task_states[client_id]["start_time"] = datetime.now()

        # 清空音频缓冲区
        self.audio_buffers[client_id] = []

        # 简化流程：不发送确认消息

        logger.info(f"ASR任务 {task_id} 已开始，等待音频数据")

    async def handle_finish_task(self, websocket, client_id, data, task_id):
        """处理结束任务消息"""
        logger.info(f"客户端 {client_id} 结束ASR任务: {task_id}")

        # 处理完整的音频数据
        if client_id in self.audio_buffers and self.audio_buffers[client_id]:
            await self.process_complete_audio(websocket, client_id, task_id)

        # 更新任务状态
        self.task_states[client_id]["is_recording"] = False
        self.task_states[client_id]["current_task_id"] = None

        # 简化流程：不发送确认消息

        logger.info(f"ASR任务 {task_id} 已结束")

    async def handle_robot_registration(self, websocket, client_id, data):
        """处理robot注册"""
        try:
            logger.info(f"客户端 {client_id} 请求注册robot")

            # 验证robot注册数据格式
            header = data.get("header", {})
            payload = data.get("payload", {})

            if not header.get("action") == "register-robot":
                await self.send_error(websocket, "Invalid action type for robot registration")
                return

            # 提取robot信息
            robot_id = payload.get("robot_id")

            # 验证必要字段
            if not robot_id:
                await self.send_error(websocket, "Missing robot_id in registration request")
                return

            # 检查robot_id是否已被注册
            if robot_id in self.robot_clients:
                # 如果已存在，先清理旧连接
                old_websocket = self.robot_clients[robot_id]
                if old_websocket != websocket:
                    logger.warning(f"Robot {robot_id} 已存在，替换旧连接")
                    # 关闭旧连接
                    try:
                        await old_websocket.close()
                    except:
                        pass

            # 注册robot
            self.robot_clients[robot_id] = websocket
            self.task_states[client_id]["robot_id"] = robot_id

            # 构建注册响应
            response = {
                "type": "robot-registration",
                "status": "success",
                "robot_id": robot_id,
                "client_id": client_id,
                "message": f"Robot {robot_id} 注册成功",
                "timestamp": datetime.now().isoformat()
            }

            # 发送注册确认响应
            await websocket.send(json.dumps(response, ensure_ascii=False))

            logger.info(f"Robot {robot_id} 注册成功，客户端ID: {client_id}")

        except Exception as e:
            logger.error(f"处理robot注册时出错: {e}")
            await self.send_error(websocket, f"处理robot注册时出错: {str(e)}")

    async def handle_nlu_result_distribution(self, websocket, client_id, data):
        """处理NLU结果分发"""
        try:
            logger.info(f"客户端 {client_id} 发送NLU结果分发请求")

            # 验证NLU结果数据格式
            header = data.get("header", {})
            payload = data.get("payload", {})

            if not header.get("action") == "nlu-result":
                await self.send_error(websocket, "Invalid action type for NLU result")
                return

            # 提取NLU结果数据
            task_id = header.get("task_id")
            target_robot_id = header.get("target_robot_id")  # 目标robot_id
            nlu_result = payload.get("nlu_result", {})

            # 验证必要字段
            if not task_id:
                await self.send_error(websocket, "Missing task_id in NLU result")
                return

            if not target_robot_id:
                await self.send_error(websocket, "Missing target_robot_id in NLU result")
                return

            # 检查目标robot是否在线
            if target_robot_id not in self.robot_clients:
                await self.send_error(websocket, f"Target robot {target_robot_id} is not online")
                return

            # 构建NLU结果分发响应
            response = {
                "type": "nlu-result-distribution",
                "status": "success",
                "task_id": task_id,
                "target_robot_id": target_robot_id,
                "nlu_result": {
                    "text": nlu_result.get("text", ""),
                    "任务类型": nlu_result.get("任务类型", "未知"),
                    "confidence": nlu_result.get("confidence", 0.0),
                    "reasoning": nlu_result.get("reasoning", ""),
                    "timestamp": nlu_result.get("timestamp", time.time())
                },
                "distribution_info": {
                    "target_robot": target_robot_id,
                    "distribution_time": datetime.now().isoformat(),
                    "status": "distributed"
                },
                "timestamp": datetime.now().isoformat()
            }

            # 向特定robot分发NLU结果
            await self.distribute_nlu_result_to_robot(target_robot_id, response)

            # 发送确认响应给发送方
            await websocket.send(json.dumps(response, ensure_ascii=False))

            logger.info(f"NLU结果分发完成: {task_id} -> robot {target_robot_id}")

        except Exception as e:
            logger.error(f"处理NLU结果分发时出错: {e}")
            await self.send_error(websocket, f"处理NLU结果分发时出错: {str(e)}")

    async def distribute_nlu_result_to_robot(self, target_robot_id, nlu_result_data):
        """向特定robot分发NLU结果"""
        try:
            if target_robot_id not in self.robot_clients:
                logger.warning(f"目标robot {target_robot_id} 不在线，跳过NLU结果分发")
                return

            target_websocket = self.robot_clients[target_robot_id]

            # 构建分发消息
            distribution_message = {
                "type": "nlu-result-delivery",
                "data": nlu_result_data,
                "timestamp": datetime.now().isoformat()
            }

            # 向目标robot发送NLU结果
            try:
                await target_websocket.send(json.dumps(distribution_message, ensure_ascii=False))
                logger.info(f"NLU结果已成功分发到robot {target_robot_id}")
            except websockets.exceptions.ConnectionClosed:
                logger.warning(f"目标robot {target_robot_id} 连接已断开，清理映射")
                del self.robot_clients[target_robot_id]
            except Exception as e:
                logger.error(f"向robot {target_robot_id} 分发NLU结果时出错: {e}")
                # 如果发送失败，清理映射
                del self.robot_clients[target_robot_id]

        except Exception as e:
            logger.error(f"分发NLU结果到robot {target_robot_id} 时出错: {e}")

    async def handle_binary_audio(self, websocket, client_id, audio_data):
        """处理二进制音频数据 - 只存储，等待finish-task信号"""
        try:
            logger.info(f"客户端 {client_id} 接收到二进制音频数据，大小: {len(audio_data)} bytes")

            # 获取当前任务ID
            task_id = self.task_states[client_id].get("current_task_id")
            if not task_id:
                # 如果没有任务ID，生成一个新的
                task_id = str(uuid.uuid4())
                self.task_states[client_id]["current_task_id"] = task_id

            # 只存储音频数据，不立即处理
            if client_id not in self.audio_buffers:
                self.audio_buffers[client_id] = []

            # 存储音频数据
            self.audio_buffers[client_id].append({
                "audio_data": audio_data,
                "timestamp": time.time(),
                "task_id": task_id
            })

            logger.info(f"音频数据已存储，等待finish-task信号，任务ID: {task_id}")

        except Exception as e:
            logger.error(f"处理二进制音频数据时出错: {e}")
            await self.send_error(websocket, f"处理音频数据时出错: {str(e)}")

    def detect_audio_format(self, audio_data):
        """检测音频格式"""
        if len(audio_data) < 4:
            return "wav"  # 默认格式

        # 检查文件头
        header = audio_data[:4]

        # MP3格式检测
        if header == b'ID3\x03' or header == b'ID3\x04':  # ID3v2
            return "mp3"
        elif audio_data[:2] == b'\xff\xfb' or audio_data[:2] == b'\xff\xfa':  # MP3 frame header
            return "mp3"

        # WAV格式检测
        elif header == b'RIFF':
            return "wav"

        # OGG格式检测
        elif header == b'OggS':
            return "ogg"

        # FLAC格式检测
        elif header == b'fLaC':
            return "flac"

        # 默认返回wav
        return "wav"

    async def process_audio_directly(self, websocket, client_id, audio_data, task_id):
        """直接处理音频数据 - 简化流程"""
        try:
            # 检测音频格式并保存文件
            audio_format = self.detect_audio_format(audio_data)
            timestamp = int(time.time())
            # 按照要求使用 sequence_id 和固定 .wav 格式
            audio_filename = f"audio_{task_id}_{timestamp}.wav"
            audio_file_path = os.path.join(self.audio_save_dir, audio_filename)

            # 确保目录存在
            os.makedirs(self.audio_save_dir, exist_ok=True)

            # 保存音频数据
            with open(audio_file_path, 'wb') as f:
                f.write(audio_data)

            # 计算音频时长
            audio_duration = 0.0
            try:
                if audio_format == "wav":
                    with wave.open(audio_file_path, 'rb') as wav_file:
                        frames = wav_file.getnframes()
                        sample_rate = wav_file.getframerate()
                        audio_duration = frames / float(sample_rate)
            except Exception as e:
                logger.warning(f"无法获取音频时长: {e}")

            # 输出处理日志
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            logger.info(f"音频文件已保存: {audio_file_path}")
            logger.info(f"文件格式: {audio_format}")
            logger.info(f"文件大小: {len(audio_data)} bytes")
            logger.info(f"音频时长: {audio_duration:.2f}秒")
            logger.info(f"任务ID: {task_id}")
            logger.info(f"文件时间戳: {timestamp}")
            logger.info(f"接收时间: {current_time}")

            # 调用ASR服务
            logger.info(f"开始ASR识别，任务ID: {task_id}")
            asr_result = await self.asr_service.recognize_audio_file(audio_file_path, task_id)

            if asr_result.get("success", False):
                recognized_text = asr_result.get("text", "")
                confidence = asr_result.get("confidence", 0.0)
                logger.info(f"ASR识别成功: {recognized_text}, 置信度: {confidence:.2f}")

                # 不再发送ASR结果给客户端，直接进行NLU分析
                logger.info(f"ASR识别完成，开始NLU任务分析")

                # 调用NLU进行任务判断
                if recognized_text.strip():
                    try:
                        logger.info(f"开始NLU任务分析: {recognized_text}")
                        nlu_result = await self.nlu_service.analyze_task(
                            text=recognized_text,
                            task_id=task_id,
                            robot_id="websocket_robot"
                        )

                        if nlu_result.get("success", False):
                            task_type = nlu_result.get("任务类型", "未知")
                            nlu_confidence = nlu_result.get("confidence", 0.0)
                            reasoning = nlu_result.get("reasoning", "")

                            logger.info(f"NLU分析成功: {task_type}, 置信度: {nlu_confidence:.2f}")

                            # 发送NLU结果给客户端 - 按照文档格式，包含ASR识别的文本
                            nlu_response = {
                                "sequence_id": task_id,
                                "robot_id": "websocket_robot",
                                "status": "success",
                                "endpoint_status": "online",
                                "text": recognized_text,
                                "confidence": nlu_confidence,
                                "任务类型": task_type,
                                "reasoning": reasoning,
                                "timestamp": datetime.now(timezone.utc).isoformat()
                            }

                            # 添加详细日志
                            logger.info(f"发送NLU成功响应给客户端 {client_id}: {nlu_response}")
                            await websocket.send(json.dumps(nlu_response, ensure_ascii=False))
                            logger.info(f"NLU成功响应已发送给客户端 {client_id}")
                        else:
                            error_msg = nlu_result.get("error", "NLU分析失败")
                            logger.error(f"NLU分析失败: {error_msg}")

                            # 发送NLU错误信息 - 按照文档格式
                            nlu_error_response = {
                                "sequence_id": task_id,
                                "robot_id": "websocket_robot",
                                "status": "failed",
                                "endpoint_status": "online",
                                "timestamp": datetime.now(timezone.utc).isoformat()
                            }
                            await websocket.send(json.dumps(nlu_error_response, ensure_ascii=False))
                    except Exception as e:
                        logger.error(f"NLU分析异常: {e}")
                        error_response = {
                            "sequence_id": task_id,
                            "robot_id": "websocket_robot",
                            "status": "failed",
                            "endpoint_status": "online",
                            "timestamp": datetime.now(timezone.utc).isoformat()
                        }
                        await websocket.send(json.dumps(error_response, ensure_ascii=False))
                else:
                    logger.warning("ASR识别结果为空，跳过NLU分析")
            else:
                error_msg = asr_result.get("error", "ASR识别失败")
                logger.error(f"ASR识别失败: {error_msg}")

                # 发送ASR错误信息 - 按照文档格式
                asr_error_response = {
                    "sequence_id": task_id,
                    "robot_id": "websocket_robot",
                    "status": "failed",
                    "endpoint_status": "online",
                    "timestamp": datetime.now(timezone.utc).isoformat()
                }

                # 添加详细日志
                logger.info(f"发送ASR错误响应给客户端 {client_id}: {asr_error_response}")

                # 检查连接状态
                if websocket.closed:
                    logger.error(f"WebSocket连接已关闭，无法发送响应给客户端 {client_id}")
                    return

                await websocket.send(json.dumps(asr_error_response, ensure_ascii=False))
                logger.info(f"ASR错误响应已发送给客户端 {client_id}")

        except Exception as e:
            logger.error(f"处理音频数据时出错: {e}")
            error_response = {
                "sequence_id": task_id,
                "robot_id": "websocket_robot",
                "status": "failed",
                "endpoint_status": "online",
                "timestamp": datetime.now(timezone.utc).isoformat()
            }
            await websocket.send(json.dumps(error_response, ensure_ascii=False))

    async def handle_audio_data(self, websocket, client_id, data):
        """处理音频数据（传统格式）"""
        try:
            audio_base64 = data.get("audio_data")
            if not audio_base64:
                await self.send_error(websocket, "缺少音频数据")
                return

            # 解码base64音频数据
            audio_bytes = base64.b64decode(audio_base64)

            # 存储到缓冲区
            if client_id not in self.audio_buffers:
                self.audio_buffers[client_id] = []

            self.audio_buffers[client_id].append(
                {
                    "timestamp": datetime.now().isoformat(),
                    "audio_data": audio_bytes,
                    "sample_rate": data.get("sample_rate", 16000),
                    "channels": data.get("channels", 1),
                    "format": data.get("format", "pcm"),
                }
            )

            # 简化流程：不发送确认消息
            logger.info(
                f"客户端 {client_id} 接收到音频数据，缓冲区大小: {len(self.audio_buffers[client_id])}"
            )

        except Exception as e:
            logger.error(f"处理音频数据时出错: {e}")
            await self.send_error(websocket, f"处理音频数据时出错: {str(e)}")

    async def handle_text_message(self, websocket, client_id, data):
        """处理文本消息"""
        text = data.get("text", "")
        logger.info(f"客户端 {client_id} 发送文本: {text}")

        # 简化流程：不发送确认消息
        # 这里可以添加文本处理逻辑，比如发送到语音合成服务

    async def handle_start_recording(self, websocket, client_id, data):
        """处理开始录音消息（传统格式）"""
        logger.info(f"客户端 {client_id} 开始录音")

        # 生成任务ID
        task_id = str(uuid.uuid4())

        # 更新任务状态
        self.task_states[client_id]["current_task_id"] = task_id
        self.task_states[client_id]["is_recording"] = True
        self.task_states[client_id]["start_time"] = datetime.now()

        # 清空之前的音频缓冲区
        self.audio_buffers[client_id] = []

        # 简化流程：不发送确认消息
        logger.info(f"录音任务已开始: {task_id}")

    async def handle_stop_recording(self, websocket, client_id, data):
        """处理停止录音消息（传统格式）"""
        logger.info(f"客户端 {client_id} 停止录音")

        task_id = self.task_states[client_id].get("current_task_id")

        # 处理完整的音频数据
        if client_id in self.audio_buffers and self.audio_buffers[client_id]:
            await self.process_complete_audio(websocket, client_id, task_id)

        # 更新任务状态
        self.task_states[client_id]["is_recording"] = False
        self.task_states[client_id]["current_task_id"] = None

        # 简化流程：不发送确认消息
        logger.info(f"录音任务已结束: {task_id}")

    # 移除心跳消息处理方法

    async def process_complete_audio(self, websocket, client_id, task_id=None):
        """处理完整的音频数据"""
        try:
            audio_chunks = self.audio_buffers[client_id]
            if not audio_chunks:
                return

            # 合并所有音频块
            combined_audio = b"".join([chunk["audio_data"] for chunk in audio_chunks])

            # 检测音频格式
            audio_format = self.detect_audio_format(combined_audio)

            # 使用接收时间作为文件名时间戳
            current_time = datetime.now()
            timestamp_str = current_time.strftime("%Y%m%d_%H%M%S")

            if audio_format == "mp3":
                # 直接保存MP3文件
                filename = f"audio_{task_id}_{timestamp_str}.mp3"
                filepath = os.path.join(self.audio_save_dir, filename)

                with open(filepath, 'wb') as f:
                    f.write(combined_audio)

                # 计算音频时长（MP3格式）
                audio_duration = len(combined_audio) / 16000  # 粗略估算
            else:
                # 保存为WAV文件
                filename = f"audio_{task_id}_{timestamp_str}.wav"
                filepath = os.path.join(self.audio_save_dir, filename)

                # 获取音频参数（使用默认值）
                sample_rate = 16000  # 默认采样率
                channels = 1  # 默认单声道

                with wave.open(filepath, "wb") as wav_file:
                    wav_file.setnchannels(channels)
                    wav_file.setsampwidth(2)  # 假设16位音频
                    wav_file.setframerate(sample_rate)
                    wav_file.writeframes(combined_audio)

                # 计算音频时长
                audio_duration = len(combined_audio) / (sample_rate * channels * 2)  # 2 bytes per sample

            # 输出处理日志
            current_time_str = current_time.strftime("%Y-%m-%d %H:%M:%S")
            logger.info(f"音频文件已保存: {filepath}")
            logger.info(f"文件格式: {audio_format}")
            logger.info(f"文件大小: {len(combined_audio)} bytes")
            logger.info(f"音频时长: {audio_duration:.2f}秒")
            logger.info(f"任务ID: {task_id}")
            logger.info(f"文件时间戳: {timestamp_str}")
            logger.info(f"接收时间: {current_time_str}")

            # 调用ASR进行语音识别
            try:
                logger.info(f"开始ASR语音识别: {filename}")
                asr_result = await self.asr_service.recognize_audio_file(filepath, task_id)

                if asr_result.get("success", False):
                    recognized_text = asr_result.get("text", "")
                    confidence = asr_result.get("confidence", 0.0)
                    logger.info(f"ASR识别成功: {recognized_text}, 置信度: {confidence:.2f}")

                    # 不再发送ASR结果给客户端，直接进行NLU分析
                    logger.info(f"ASR识别完成，开始NLU任务分析")

                    # 调用NLU进行任务判断
                    if recognized_text.strip():
                        try:
                            logger.info(f"开始NLU任务分析: {recognized_text}")
                            nlu_result = await self.nlu_service.analyze_task(
                                text=recognized_text,
                                task_id=task_id,
                                robot_id="websocket_robot"
                            )

                            if nlu_result.get("success", False):
                                task_type = nlu_result.get("任务类型", "未知")
                                nlu_confidence = nlu_result.get("confidence", 0.0)
                                reasoning = nlu_result.get("reasoning", "")

                                logger.info(f"NLU分析成功: {task_type}, 置信度: {nlu_confidence:.2f}")

                                # 发送NLU结果给客户端
                                nlu_response = {
                                    "sequence_id": task_id,
                                    "robot_id": "websocket_robot",
                                    "status": "success",
                                    "endpoint_status": "online",
                                    "text": recognized_text,
                                    "任务类型": task_type,
                                    "confidence": nlu_confidence,
                                    "reasoning": reasoning,
                                    "timestamp": datetime.now().isoformat(),
                                }
                                await websocket.send(json.dumps(nlu_response, ensure_ascii=False))
                            else:
                                error_msg = nlu_result.get("error", "NLU分析失败")
                                logger.error(f"NLU分析失败: {error_msg}")

                                # 发送NLU错误信息
                                nlu_error_response = {
                                    "sequence_id": task_id,
                                    "robot_id": "websocket_robot",
                                    "status": "failed",
                                    "endpoint_status": "online",
                                    "text": recognized_text,
                                    "error": error_msg,
                                    "timestamp": datetime.now().isoformat(),
                                }
                                await websocket.send(json.dumps(nlu_error_response))

                        except Exception as e:
                            logger.error(f"NLU调用异常: {e}")
                            nlu_error_response = {
                                "sequence_id": task_id,
                                "robot_id": "websocket_robot",
                                "status": "failed",
                                "endpoint_status": "online",
                                "text": recognized_text,
                                "error": f"NLU服务异常: {str(e)}",
                                "timestamp": datetime.now().isoformat(),
                            }
                            await websocket.send(json.dumps(nlu_error_response))
                else:
                    error_msg = asr_result.get("error", "ASR识别失败")
                    logger.error(f"ASR识别失败: {error_msg}")

                    # 发送错误信息
                    error_response = {
                        "type": "asr_error",
                        "task_id": task_id,
                        "error": error_msg,
                        "timestamp": datetime.now().isoformat(),
                    }
                    await websocket.send(json.dumps(error_response))

            except Exception as e:
                logger.error(f"ASR调用异常: {e}")
                error_response = {
                    "type": "asr_error",
                    "task_id": task_id,
                    "error": f"ASR服务异常: {str(e)}",
                    "timestamp": datetime.now().isoformat(),
                }
                await websocket.send(json.dumps(error_response))

            # 简化流程：不发送确认消息
            logger.info(f"音频处理完成: {filename}, 时长: {audio_duration:.2f}秒")

        except Exception as e:
            logger.error(f"处理完整音频时出错: {e}")
            await self.send_error(websocket, f"处理完整音频时出错: {str(e)}")

    async def send_error(self, websocket, error_message):
        """发送错误消息 - 按照文档格式"""
        error_response = {
            "sequence_id": "error",
            "robot_id": "websocket_robot",
            "status": "failed",
            "endpoint_status": "online",
            "timestamp": datetime.now(timezone.utc).isoformat()
        }
        await websocket.send(json.dumps(error_response, ensure_ascii=False))

    async def broadcast_message(self, message):
        """广播消息给所有连接的客户端"""
        if self.clients:
            await asyncio.gather(
                *[client.send(json.dumps(message)) for client in self.clients],
                return_exceptions=True,
            )

    async def start_server(self):
        """启动WebSocket服务器"""

        async def handler(websocket):
            # 获取路径信息
            path = websocket.path if hasattr(websocket, 'path') else "/ws"

            # 只处理 /ws
            if path != "/ws":
                # 拒绝非 /ws 路径
                await websocket.close(code=1008, reason="Forbidden path")
                logger.warning(f"拒绝访问路径: {path}")
                return

            # 调用原来的处理函数
            await self.handle_client(websocket, path)

        logger.info(f"云侧WebSocket服务器已启动，监听地址: ws://{self.host}:{self.port}/ws")
        logger.info(f"音频文件将保存到: {os.path.abspath(self.audio_save_dir)}")
        logger.info("支持ASR任务管理和传统音频传输格式")

        # 配置WebSocket服务器参数，解决超时问题
        server = await websockets.serve(
            handler,
            self.host,
            self.port,
            ping_interval=20,  # 每20秒发送ping
            ping_timeout=10,  # ping超时时间10秒
            close_timeout=10,  # 关闭超时时间10秒
            max_size=2 ** 20,  # 最大消息大小1MB
            max_queue=32  # 最大队列大小
        )
        logger.info("服务器已启动，等待连接...")

        try:
            await server.wait_closed()
        except KeyboardInterrupt:
            logger.info("收到中断信号，正在关闭服务器...")
        finally:
            server.close()
            await server.wait_closed()


async def main():
    """主函数"""
    server = CloudWebSocketServer()
    await server.start_server()


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("服务器已停止")
